// @ts-nocheck
import {Puerts, System, UnityEngine} from "csharp";
import {ComponentMgr} from "./componentMgr";
import {$typeof} from "puerts";
import Transform = UnityEngine.Transform;
import GameObject = UnityEngine.GameObject;
import JsBehaviour = Puerts.JsBehaviour;
import TypeScript = Puerts.TypeScript;
/*
完整的MonoBehaviour生命周期 ;
[  Awake,Start,OnEnable,OnDisable,OnDestroy  ];
[  Update,LateUpdate,FixedUpdate ] 由comgponentmgr管理 ;
自动绑定到jsbehaviour ;
注: 在构造函数中调用  applyArgs() 将jsbehaviour绑定的同名数据绑定到定义的ts中.
 */
export abstract class Component {
    public readonly behaviour: Puerts.JsBehaviour = null;
    public readonly transform:Transform = null
    public readonly gameObject:GameObject = null
    public isActive :boolean = true;
    //life circle
    protected Awake?():void;
    protected Start?():void;
    protected OnEnable?():void;
    protected OnDisable?():void;
    protected OnDestroy?():void;
    protected Update?(deltaTime:number):void;
    protected LateUpdate?(deltaTime:number):void;
    protected FixedUpdate?(fixedTime:number):void;
    protected constructor(behaviour: Puerts.JsBehaviour) {
        this.behaviour = behaviour;
        this.transform = behaviour.transform
        this.gameObject = behaviour.gameObject
        this.isActive = this.gameObject.activeInHierarchy && behaviour.isActiveAndEnabled;
        if(this.Awake)
            behaviour._jsAwake = this.Awake.bind(this);
        if(this.Start)
            behaviour._jsStart = this.Start.bind(this);
        behaviour._jsOnEnable = (()=>{
            this.isActive = this.gameObject.activeInHierarchy && this.behaviour.isActiveAndEnabled;
            if(this.OnEnable)
                this.OnEnable();
        }).bind(this)
        behaviour._jsOnDisable = (()=> {
            this.isActive = false;
            if(this.OnDisable)
                this.OnDisable();
        }).bind(this)
        behaviour._jsOnDestroy = (()=>{
            if(this.OnDestroy)
                this.OnDestroy();
            ComponentMgr.Instance.Off(this.gameObject.GetHashCode(),this)
        }).bind(this)
        if(this.Update)
        {
            this._Update = this.Update;
            this.Update = ((dt)=>{
                if(this.isActive)
                    this._Update(dt);
            }).bind(this)
        }
        if(this.LateUpdate)
        {
            this._LateUpdate = this.LateUpdate;
            this.LateUpdate = ((dt)=>{
                if(this.isActive)
                    this._LateUpdate(dt);
            }).bind(this)
        }
        if(this.FixedUpdate)
        {
            this._LateUpdate = this.FixedUpdate;
            this.FixedUpdate = ((fdt)=>{
                if(this.isActive)
                    this._FixedUpdate(fdt);
            }).bind(this)
        }
        ComponentMgr.Instance.On(this.gameObject.GetHashCode(), this);//让mgr持有
    }
    applyArgs(){
        let args = this.behaviour.args;

        if(args !==null && args.Length > 0){

            for (let i = 0; i < args.Length; i++) {
                let arg = args.get_Item(i)
                Object.defineProperty(this,arg.name,{
                    value:arg.value,
                    writable : true,
                    enumerable :true
                })
            }
        }
    }
    //多个component 将挂载多个jsbehaviour 以避免behaviour钩子被替换
    AddComponent<T extends Component|UnityEngine.Component>(compType:{new(...args: any[])}|System.Type,module:string):T{
        if(compType.IsSubclassOf($typeof(UnityEngine.Component))){
            let cmp = this.gameObject.AddComponent(compType)
            if(cmp === null)
                return null;
            return cmp as T;
        }
        let newBehaviour = this.gameObject.AddComponent($typeof(JsBehaviour)) as JsBehaviour;
        newBehaviour.module = TypeScript.CreateFromFile(module)
        newBehaviour.InitAwake()
        return ComponentMgr.Instance.GetComponent(this.gameObject,compType)
    }
    GetComponent<T extends Component|UnityEngine.Component>(compType:{new(...args: any[])}|System.Type):T{
        if(compType.IsSubclassOf($typeof(UnityEngine.Component))){
            let cmp = this.gameObject.GetComponent(compType)
            if(cmp === null)
                return null;
            return cmp as T;
        }
        return ComponentMgr.Instance.GetComponent<T>(this.gameObject,compType)
    }
    GetComponents<T extends Component|UnityEngine.Component>(compType:{new(...args: any[])}|System.Type):T[]{
        if(compType.IsSubclassOf($typeof(UnityEngine.Component))){
            let cmps:System.Array$1<UnityEngine.Component> = this.gameObject.GetComponents(compType)
            if(cmps === null)
                return null;
            let arr:T[]  = []

            for(var i=0;i<cmps.Length;i++)
                arr.push(cmps.get_Item(i) as T)
            return arr;
        }
        return ComponentMgr.Instance.GetComponents<T>(this.gameObject,compType)
    }

    Instantiate = UnityEngine.GameObject.Instantiate;
}
